﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;

namespace BenchmarkApp.Utils
{
    public static class Results
    {
        /// <summary>
        /// Measures the accuracy of the detected result
        /// </summary>
        /// <param name="originalChars">The characters that the XML tells us are present in the picture</param>
        /// <param name="detectedChars">The characters that we have detected in the picture</param>
        /// <returns></returns>
        public static double measureOcrPrecision(String[] originalChars, String[] detectedChars)
        {
            if ((originalChars.GetLength(0) == 1) && (detectedChars.GetLength(0) == 1))//This means we have only ONE number plate to compare.
            {
                double d = ((100 * (compareString(originalChars[0], detectedChars[0])) / removeCharsFromString(originalChars[0], new char[]{'-', 'I'}).Length));
                return d;
            }

            int numberOfPlatesInPicture = originalChars.GetLength(0);
            int numPlatesFound = 0;
            int numOfCharactersIdentified = 0;

            if (numberOfPlatesInPicture == detectedChars.GetLength(0))
            {
                foreach (String s in detectedChars)
                {
                    foreach (String t in originalChars)
                    {
                        if (compareString(s, t) == s.Length)
                        {
                            numPlatesFound++;
                            //Console.WriteLine("YAY: " + s);
                        }
                        numOfCharactersIdentified += compareString(s, t);
                    }
                }
                //There are as much number plates detected in the picture as provided in the xml, find a match
            }
            else if (numberOfPlatesInPicture < detectedChars.GetLength(0))
            {
                //There are more detected plates than provided in the XML, find a match
                Console.WriteLine("more plates found, WHAT SHOULD I DOOOO?");
            }
            else
            {
                List<Double> percentages = new List<Double>();
                foreach (String s in originalChars)
                {
                    foreach (String t in detectedChars)
                    {
                        if (compareString(s, t) >= (t.Length - 3)) //If there are less matches than t.Length -3 there probably isn't a match. Or OCR sucks.
                        {
                            percentages.Add((100 * (compareString(s, t)) / t.Length)); //Compare to the length of t because extra detected channels would yield a 100% accuracy rate fi the other characters DO match!
                        }
                        else
                        {
                            Console.WriteLine("Not enoughmatchingssssss");
                            //TODO: Do some weird matching with a different amount of characters
                        }
                    }
                }
                return percentages.Average();
            }
            return 0;

        }


        /// <summary>
        /// Compares two strings and returns the amount of matching characters.
        /// </summary>
        /// <param name="first">The reference value</param>
        /// <param name="second">The value to compare to</param>
        /// <returns></returns>
        public static int compareString(String first, String second)
        {
            int i = 0;
            String Myfirst = removeCharsFromString(first, new char[] { 'I', '-' });
            String Mysecond = removeCharsFromString(second, new char[] { 'I', '-' });

            if (Myfirst.Length == Mysecond.Length)
            {
                for (int j = 0; j <= (Myfirst.Length - 1); j++)
                {
                    if (Myfirst[j] == Mysecond[j])
                    {
                        i++;
                    }
                }
            }
            else
            {
                for (int j = 0; (j <= (Mysecond.Length - 1) && j <= (Myfirst.Length - 1)); j++)
                {
                    if (Myfirst[j] == Mysecond[j] || Myfirst.IndexOf(Mysecond[j]) != -1)
                    {
                        i++;
                    }
                }
                //Console.WriteLine("Paniek! " + Myfirst.Length + " " + Mysecond.Length);
            }
            return i;
        }


        /// <summary>
        /// Creates a new XmlElement that represents a test result.
        /// </summary>
        /// <param name="filename">Filename of the tested image</param>
        /// <param name="topLeft">Coordinates of the TopLeft corner of the number plate</param>
        /// <param name="topRight">Coordinates of the TopRigh corner of the number plate</param>
        /// <param name="bottomLeft">Coordinates of the BottomLeft corner of the number plate</param>
        /// <param name="bottomRight">Coordinates of the BottomRight corner of the number plate</param>
        /// <param name="ocrResults">The letters that have been recognised in the provided blobs</param>
        /// <param name="executionTime">The time in ms that it took to process the image</param>
        /// <returns>An XmlElement containing all the provided information.</returns>
        public static XmlNode createResultXmlNode(String filename, NumberPlate[] np, long executionTime, XMLProvider xmlp)
        {
            XElement image = new XElement("image", new XAttribute("filename", filename));
            foreach (NumberPlate plate in np)
            {
                XElement upperLeft = new XElement("upperLeft", new XAttribute("x", plate.UpperLeft.X), new XAttribute("y", plate.UpperLeft.Y));
                XElement upperRight = new XElement("upperRight", new XAttribute("x", plate.UpperRight.X), new XAttribute("y", plate.UpperRight.Y));
                XElement lowerLeft = new XElement("lowerLeft", new XAttribute("x", plate.LowerLeft.X), new XAttribute("y", plate.LowerLeft.Y));
                XElement lowerRight = new XElement("lowerRight", new XAttribute("x", plate.LowerRight.X), new XAttribute("y", plate.LowerRight.Y));
                XElement location = new XElement("location", upperLeft, upperRight, lowerLeft, lowerRight);
                XElement license_plate = new XElement("license_plate");
                license_plate.Add(location);
                license_plate.Add(new XElement("text", removeCharsFromString(plate.DetectedCharacters, new char[]{'-', 'I'})));
                image.Add(license_plate);
            }
            XElement execution_time = new XElement("execution_time", "" + executionTime + " ms");
            image.Add(execution_time);

            XmlDocument doc = new XmlDocument();
            XmlElement element = doc.ReadNode(image.CreateReader()) as XmlElement;
            return xmlp.Document.ImportNode(element, true);
        }


        public static String removeCharsFromString(String stringToRemoveTextFrom, char[] charsToRemove)
        {
            String myString = "" + stringToRemoveTextFrom;
            
            foreach (char c in charsToRemove)
            {
                while (myString.IndexOf(c) != -1)
                {
                    myString = myString.Remove(myString.IndexOf(c), 1);
                    //Console.WriteLine(myString);
                }
            }
            return myString;
        }
    }
}
